{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 决策树"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 是一种常见的机器学习算法，顾名思义，决策树是基于树的结构来进行决策的，这正好是人类在解决问题的很自然的方式，对于一个问题的解，我们常常会进行一系列判断，最终得到决策。\n",
    "决策树的构成需要以当前的一个特征作为树的各个节点，那么如何取得各个的特征成为难点。\n",
    "\n",
    "### 首先介绍ID3算法\n",
    "\n",
    "ID3算法使用信息增益来取得最好的特征，求信息增益，首先求信息熵\n",
    "$$\n",
    "Ent(D) = -\\sum{p_k\\log{2}{p_k}}\n",
    "$$\n",
    "那么，信息增益为\n",
    "$$\n",
    "Gain(D,a) = Ent(D)-\\sum{\\frac{D^v}{D}Ent(D^v)}\n",
    "$$\n",
    "其中，a为某一个特征（属性）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 计算信息熵\n",
    "def calculate_entropy(y):\n",
    "    log2 = math.log2\n",
    "    unique_labels = np.unique(y)\n",
    "    entropy = 0\n",
    "    for label in unique_labels:\n",
    "        count = len(y[y == label])\n",
    "        p = count / len(y)\n",
    "        entropy += -p * log2(p)\n",
    "    return entropy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 定义树的节点\n",
    "class DecisionNode():\n",
    "    def __init__(self, feature_i=None, threshold=None,\n",
    "                 value=None, true_branch=None, false_branch=None):\n",
    "        self.feature_i = feature_i          \n",
    "        self.threshold = threshold         \n",
    "        self.value = value                 \n",
    "        self.true_branch = true_branch     \n",
    "        self.false_branch = false_branch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def divide_on_feature(X, feature_i, threshold):\n",
    "    split_func = None\n",
    "    if isinstance(threshold, int) or isinstance(threshold, float):\n",
    "        split_func = lambda sample: sample[feature_i] >= threshold\n",
    "    else:\n",
    "        split_func = lambda sample: sample[feature_i] == threshold\n",
    "\n",
    "    X_1 = np.array([sample for sample in X if split_func(sample)])\n",
    "    X_2 = np.array([sample for sample in X if not split_func(sample)])\n",
    "\n",
    "    return np.array([X_1, X_2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 超类\n",
    "class DecisionTree(object):\n",
    "    def __init__(self, min_samples_split=2, min_impurity=1e-7,\n",
    "                 max_depth=float(\"inf\"), loss=None):\n",
    "        self.root = None  #根节点\n",
    "        self.min_samples_split = min_samples_split\n",
    "        self.min_impurity = min_impurity\n",
    "        self.max_depth = max_depth\n",
    "        # 计算值 如果是分类问题就是信息增益，回归问题就基尼指数\n",
    "        self._impurity_calculation = None\n",
    "        self._leaf_value_calculation = None #计算叶子\n",
    "        self.one_dim = None\n",
    "        self.loss = loss\n",
    "\n",
    "    def fit(self, X, y, loss=None):\n",
    "        self.one_dim = len(np.shape(y)) == 1\n",
    "        self.root = self._build_tree(X, y)\n",
    "        self.loss=None\n",
    "\n",
    "    def _build_tree(self, X, y, current_depth=0):\n",
    "        \"\"\"\n",
    "        递归求解树\n",
    "        \"\"\"\n",
    "\n",
    "        largest_impurity = 0\n",
    "        best_criteria = None\n",
    "        best_sets = None\n",
    "        \n",
    "        if len(np.shape(y)) == 1:\n",
    "            y = np.expand_dims(y, axis=1)\n",
    "\n",
    "        Xy = np.concatenate((X, y), axis=1)\n",
    "\n",
    "        n_samples, n_features = np.shape(X)\n",
    "\n",
    "        if n_samples >= self.min_samples_split and current_depth <= self.max_depth:\n",
    "            # 计算每一个特征的增益值\n",
    "            for feature_i in range(n_features):\n",
    "                feature_values = np.expand_dims(X[:, feature_i], axis=1)\n",
    "                unique_values = np.unique(feature_values)\n",
    "\n",
    "                for threshold in unique_values:\n",
    "                    Xy1, Xy2 = divide_on_feature(Xy, feature_i, threshold)\n",
    "                    \n",
    "                    if len(Xy1) > 0 and len(Xy2) > 0:\n",
    "                        y1 = Xy1[:, n_features:]\n",
    "                        y2 = Xy2[:, n_features:]\n",
    "\n",
    "                        # 计算增益值\n",
    "                        impurity = self._impurity_calculation(y, y1, y2)\n",
    "\n",
    "                        if impurity > largest_impurity:\n",
    "                            largest_impurity = impurity\n",
    "                            best_criteria = {\"feature_i\": feature_i, \"threshold\": threshold}\n",
    "                            best_sets = {\n",
    "                                \"leftX\": Xy1[:, :n_features],  \n",
    "                                \"lefty\": Xy1[:, n_features:],   \n",
    "                                \"rightX\": Xy2[:, :n_features],  \n",
    "                                \"righty\": Xy2[:, n_features:]   \n",
    "                                }\n",
    "\n",
    "        if largest_impurity > self.min_impurity:\n",
    "            true_branch = self._build_tree(best_sets[\"leftX\"], best_sets[\"lefty\"], current_depth + 1)\n",
    "            false_branch = self._build_tree(best_sets[\"rightX\"], best_sets[\"righty\"], current_depth + 1)\n",
    "            return DecisionNode(feature_i=best_criteria[\"feature_i\"], threshold=best_criteria[\n",
    "                                \"threshold\"], true_branch=true_branch, false_branch=false_branch)\n",
    "        \n",
    "        # 计算节点的目标值\n",
    "        leaf_value = self._leaf_value_calculation(y)\n",
    "        \n",
    "        \n",
    "        return DecisionNode(value=leaf_value)\n",
    "\n",
    "\n",
    "    def predict_value(self, x, tree=None):\n",
    "        \"\"\"\n",
    "        预测\n",
    "        \"\"\"\n",
    "\n",
    "        if tree is None:\n",
    "            tree = self.root\n",
    "\n",
    "        if tree.value is not None:\n",
    "            return tree.value\n",
    "\n",
    "        feature_value = x[tree.feature_i]\n",
    "\n",
    "        branch = tree.false_branch\n",
    "        if isinstance(feature_value, int) or isinstance(feature_value, float):\n",
    "            if feature_value >= tree.threshold:\n",
    "                branch = tree.true_branch\n",
    "        elif feature_value == tree.threshold:\n",
    "            branch = tree.true_branch\n",
    "\n",
    "        return self.predict_value(x, branch)\n",
    "\n",
    "    def predict(self, X):\n",
    "        y_pred = []\n",
    "        for x in X:\n",
    "            y_pred.append(self.predict_value(x))\n",
    "        return y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ClassificationTree(DecisionTree):\n",
    "    def _calculate_information_gain(self, y, y1, y2):\n",
    "        # 计算信息增益\n",
    "        p = len(y1) / len(y)\n",
    "        entropy = calculate_entropy(y)\n",
    "        info_gain = entropy - p * calculate_entropy(y1) - (1 - p) * calculate_entropy(y2)\n",
    "\n",
    "        return info_gain\n",
    "\n",
    "    def _majority_vote(self, y):\n",
    "        most_common = None\n",
    "        max_count = 0\n",
    "        for label in np.unique(y):\n",
    "            # 投票决定当前的节点为哪一个类\n",
    "            count = len(y[y == label])\n",
    "            if count > max_count:\n",
    "                most_common = label\n",
    "                max_count = count\n",
    "        \n",
    "        return most_common\n",
    "\n",
    "    def fit(self, X, y):\n",
    "        self._impurity_calculation = self._calculate_information_gain\n",
    "        self._leaf_value_calculation = self._majority_vote\n",
    "        super(ClassificationTree, self).fit(X, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 分类决策树演示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from sklearn import datasets\n",
    "from sklearn.cross_validation import train_test_split\n",
    "from sklearn.metrics import accuracy_score\n",
    "data = datasets.load_iris()\n",
    "X = data.data\n",
    "y = data.target\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4)\n",
    "clf = ClassificationTree()\n",
    "clf.fit(X_train, y_train)\n",
    "y_pred = clf.predict(X_test)\n",
    "accuracy = accuracy_score(y_pred, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.94999999999999996"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "accuracy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### emmmm 看起来还不错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 那么，什么是决策时回归呢？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 我们一般使用决策树进行决策，很少用其来进行回归，如果是回归问题就使用基尼指数\n",
    "$$\n",
    "Gini = 1- \\sum{{p_k}^2}\n",
    "$$\n",
    "那么 属性a的基尼指数为\n",
    "$$\n",
    "Gini_index(D,a) = \\sum{\\frac{D^v}{D}Gini(D^v)}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def calculate_variance(X):\n",
    "    \"\"\" Return the variance of the features in dataset X \"\"\"\n",
    "    mean = np.ones(np.shape(X)) * X.mean(0)\n",
    "    n_samples = np.shape(X)[0]\n",
    "    variance = (1 / n_samples) * np.diag((X - mean).T.dot(X - mean))\n",
    "    \n",
    "    return variance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class RegressionTree(DecisionTree):\n",
    "    def _calculate_variance_reduction(self, y, y1, y2):\n",
    "        var_tot = calculate_variance(y)\n",
    "        var_1 = calculate_variance(y1)\n",
    "        var_2 = calculate_variance(y2)\n",
    "        frac_1 = len(y1) / len(y)\n",
    "        frac_2 = len(y2) / len(y)\n",
    "\n",
    "        # 使用方差缩减\n",
    "        variance_reduction = var_tot - (frac_1 * var_1 + frac_2 * var_2)\n",
    "\n",
    "        return sum(variance_reduction)\n",
    "\n",
    "    def _mean_of_y(self, y):\n",
    "        value = np.mean(y, axis=0)\n",
    "        return value if len(value) > 1 else value[0]\n",
    "\n",
    "    def fit(self, X, y):\n",
    "        self._impurity_calculation = self._calculate_variance_reduction\n",
    "        self._leaf_value_calculation = self._mean_of_y\n",
    "        super(RegressionTree, self).fit(X, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from sklearn.metrics import mean_squared_error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "data = pd.read_csv('TempLinkoping2016.txt', sep=\"\\t\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "time = np.atleast_2d(data[\"time\"].as_matrix()).T\n",
    "temp = np.atleast_2d(data[\"temp\"].as_matrix()).T\n",
    "\n",
    "X = time\n",
    "y = temp[:, 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model = RegressionTree()\n",
    "model.fit(X_train, y_train)\n",
    "y_pred = model.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "mse = mean_squared_error(y_test, y_pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7.4523636363636365"
      ]
     },
     "execution_count": 131,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAD8CAYAAAB0IB+mAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3X+QHOV5J/DvM8MKCUuxLLSsMNZKAq2XW5NYwJ4Fh2RL\nQXtyqJQJqSRlRBkXSp2ihARflU3Zl1RhyqlU+U7c+Y4Ktiw7wsZG4uzYRMQh3lpxEggFSV5+xIjB\na60kLxKI1UqLYfkhazXz3B8zPert7Z7pnv7d/f1UUWhnZvvHzszTbz/v+z6vqCqIiCj7CnEfABER\nRYMBn4goJxjwiYhyggGfiCgnGPCJiHKCAZ+IKCcY8ImIcoIBn4goJxjwiYhy4oK4D8Bs/vz5unjx\n4rgPg4goVZ599tlTqtre7HWJCviLFy/G4OBg3IdBRJQqIjLi5nVM6RAR5QQDPhFRTjDgExHlBAM+\nEVFOMOATEeUEAz4RUU4kalgmEQVroDSKPYfGsLKrHX09HXEfDsWMAZ/IJEsBcqA0iru2P4/3Jsv4\n4eBx3H/r1ak/J/KHKR2iGiNAPvTMCO7a/jwGSqNxH5Ivew6N4b3JMgDgvcky9hwai/mIKG4M+EQ1\nWQuQK7vaMautCACY1VbEyq6mM+8p45jSIapZ2dWOHw4ex3uT5UwEyL6eDtx/69WZSVGRf6KqcR9D\nXW9vr7KWDsUpSzl8yg8ReVZVe5u9ji18IpO+ng4Gesos5vCJiHKCLXwiE6Z0KMvYwieqydqwTCIr\nBnyimrCHZQ6URnHPjoO8kFBsfAd8EVkoIrtEpCQiL4nI52qPzxORARE5VPv/B/wfLlF4why3zrsH\nSoIgWvjnAHxeVXsAXAfgThHpAfAlAE+oaheAJ2o/EyWWMW799usXBV6GIGuTuiidfHfaquoJACdq\n/54QkZcBXAbgZgCrai/7LoDdAL7od3+UP1F2pIYxLHOgNIpj4+9iRrGAs+UKZrUVMWdmG+7ZcZCd\nwxSpQCdeichiAE8BuArAK6o6t/a4AHjD+NnyOxsAbACAzs7Oa0dGXK3FSzlhLgA2q62YugJg5uOf\nUSzghqUXo+eD78fWp4+m9pwoedxOvAqs01ZEZgP4EYD/qqpvmZ/T6lXF9sqiqltUtVdVe9vb0z2V\nnYKX9lSI+fjPlit47dfvofTam6k+J0qvQAK+iLShGuwfVtUf1x4eFZFLa89fCuBkEPuifDF3pBYF\nmDOzbcrzSR/5Yj5+ABgafRt7h09jRrH61ctCzR5KjyBG6QiAfwDwsqr+L9NTjwH4bO3fnwWww+++\nKH/6ejqwfsUSFAuCsgJbnz5aD+5hjXwJ8iJidAR3d8yuP3a2XMENSy8OpXO4FUm/aFJwgmjh3wDg\nMwB+V0ReqP13E4CvAugTkUMA1tR+JvJs4swkypVqRtCcAgkj3RPGRaSvpwNfWHvllCGf65Yvwldu\nvgoAYg225vO98+HncMeDBxj4MyyIUTpPAxCHp2/0u30ip7LFYZQztruIBNECtytVbO7QfXjfCDau\nWoq713b73pcX1j6GXUNj2HdkPBF3HhQ81tKhxHOq6x5Gvfcwa+Jbh3yag21Zgc1PHsayhXMjDbTm\n8zUEeaGjZGE9fKIaY7z/nJltmDgz6eki0spcgYHSKDZ+bxBl01fw9uvPp3qiMlAaxf1P/BIvvfYW\nKgoOFU0h1sMn8sDPeP9WFwvv6+nAxlVLsfnJwyhXtH5HEUfFzuGT76Ci1ZFQ61csYbDPKBZPI4K/\nDmA/v7ts4Vx8vGs+Vne34/5brwaAyGvuWFNLE2cmQ98nxYMBnwj+Cqe1+rub+oew8XuD9Y5SYPrF\nY9v+8Geec7Hz/GAOn3KlUZ7eKZXiJsXiNQ0zUBrFxu8/Wx9uClTz9yu72nHnw8/hbLkCAJhRLOCB\n264JPcXChV/SjTl8Igtzrt1gzrnbFU5zm593KrrmFEj3HBqbEuyLgvprblh6MXYNVdNCZ8sV1yNm\n/ARtruWbD0zpUG6Y0yWGZjl3P/n5RpO4ppSMKAg2rlpaD7jrli/ynGJhvX1ygy18ikUcKQS7MefN\nAqqfcfmNJnE1mkPQyvwCu9w/UzRkxRw+RS7OksdOOfxGF6BWL05BnafbPgRzGWYA9dr7XoeYGh3F\n65Yv4sUiJdzm8BnwKXL37DiIh545P/okqMlGQQdm8/YAtLxtPy1tLxcNY1/Hxt+t9wEA7v++A6XR\nWDqMyT922lJiBVW+wBqQW5n8BADb9o/Y5umN7T1y4BiAaovZbtuNgrrfzlC7Y3PanrGvTf1DeOqX\nYyirfcqqUUeyEeyN82WJhWxhwKfIBVEDxzp65rrL57VU9GygNIq9w6frP88oFrCyq31aUTGDddub\n+ofqM2UfOXAMNyy9OLBUiNOxNUs/bX36KMpa7Qy2zpptNOpoZVc7HjlwbEoLn2Pys4UBn2Lht+Vr\n7aQEqq1ZL3cNA6VR3Nf/iykB/YalF9ePy7gLsebEjW0PlEaxefdwvRaOUW1y7/BpdC+YjfmzL2wp\n+JtTM9ZjAxrfyUyZNVvRabNmm3UkP3DbNczhZxgDPqWSNS20bvkirFu+yPVdg92YfGM7wPS7EGBq\nDt+4WJRtusDOlit48dXqKp9PDo3hz1e7L3ts7Xw1L3xunF+jO5lm6bJmz3M8frYx4FMqNSqZ7IZ1\nTP5lc2fi3k9dNW14pPVnwP5iUQBQKAjOVaZeASrwVvbYmkpa3d2OhfMumnKOzQJ2o3SZsYLYztLr\nWNOzgME9ZwIJ+CKyFcDvAzipqlfVHrsXwH8BYAwX+GtVfTyI/REB/lqj1nz12MRZ179rN4Hrz1cv\nxbKFc2vj309NCfzlirruU7C7c3Eaoz9nZlu9g9m462iWjjFy/O9NlvHK+NHI6+9TvIJq4X8HwN8D\neMjy+NdU9b6A9kEUGLclDOw6SFd2tePh/a9MKY0wcWayfgGyqy/vtk9hz6ExrF+xpGE9fuMxcy5/\n/Yol+NZTR+oXsL3Dp22HVIa1ohelQyABX1WfEpHFQWyLKCrrli/CviPjjukRpxEtfT0d2PiJK+od\nttbfNQf+VvoU3EyWsgbunaXXXQ2pbGVILAurZUfYOfy/EpHbAQwC+LyqvhHy/ohca5bvbtQavntt\nN5YtnNswEHpJOXlteVsD95qeBTh66kjTIZVeh8RaL3rN7j4o2QKbaVtr4f/ElMPvAHAKgAL4WwCX\nqup6m9/bAGADAHR2dl47MhJ+/W8iN8wzT8OeddpKGQZrmYg5M9tQeu1NANNz+K2WjrDOii4WpL46\nl90x8m4gHrHPtFXVerk+EfkWgJ84vG4LgC1AtbRCWMdDlORg1KzlbXfs1lx+oyDsNHbf6TnzxcSY\n31AU1Pst7O5CWl3qkaITWsAXkUtV9UTtx1sAHAxrX0TNbOofqufc3QYjc6mBKMoMOKWAGgVSN6kg\np9cYcwkalZWY1Vasp3HmzGyrj/Cxy/+zQzj5ghqWuR3AKgDzReQ4gC8DWCUiy1BN6fwKwJ8FsS8i\nrwZKo9XyB7X7R7fByK6DM467hEaB1E0nrNN52E08s5aVeG+yjIkzk/Xia436LebMbKveBXgYmUTR\nCmqUzq02D/9DENsmaoU5MDutLtWMNc3ywrFf1+vmRJmyaBTU3XTC2r3mnh0HpwT77o7Z+MLaK5tO\n7mp0F9Kohg8lA2faUubYjSyp56ELgo2fuMJ1MDIPsTTXzYkyZeFm9myz4zCngIDpFxFzsG9lJI85\nNWRXw4eSgQGfQhd1GsQuJeG3OueeQ2NT6uYUCxJpysJvjRu7fgC/FxHrdg1M5yQXAz6FKo6RG3Yp\nEHMAa+UCZN5mUeDpLiEJ7PoBvnLzVb7PwVpmwpoaomRhwKdQ+Rm54RSYmwXsRimJVi9AXtMcSRPU\nojNmA6VRHBt/d0pFTwb7ZGPAp1C1GmgajQ93E7CdUhJ+LkB+0ypxCvqCZS3jvLq7nfXzU4ABn0LV\naqBxCsxuAnajO4AwWrppEUQ/gHnkk7mM88J5FzHYpwADPoWu0VA+r4F5Si69IJgzs23aNhvdAaQ9\nNROXRiOf8nbhTDMGfIpFq4G5r6e6gMfm3cMoVxRbn55a093NHUAaUzNxl4UIY+QTRa8Q9wFQPtkF\nZrNGAW7izOS08fCGlV3tmNVWBJCd4YHGxfGhZ0Zw58PP4Y4HD2CgNNr8FwNk93ft6+mYNtJnoDSK\ne3YcjPz4yB0GfIpFo8BsDnB3bX9+WvBo9LvGncHt1y/KTPEua75819CY7d8lTG7+rs3eN4ofUzoU\ni0a59GZpmVZmnsadEvHD3G9h8DLCKKhzb5YKY/G05GPAp9g4BRA3I2m85OHTXrbXuMBt2z+CvcOn\n62Pe3a5WFcS5Wy8aTks/5nUEVFow4FPsrMEj6JE0WWh5mmv6ePm7BHHudiN0jDLJ1qUf2ZGbbAz4\nFKtG68YGFTCy1PL0+ncJ4tzt1s91uoikcQRUnjDgU6y8tkBbyUfnueUZxLnbrZ/7yrjzQiiUXIGt\naRuE3t5eHRwcjPswKGADpVFs219dF9VurVW3a7m2su4rBcNNDt/ptRQ+t2vaBhLwRWQrgN8HcNK0\niPk8AP8XwGJUV7z6E1V9o9F2GPCzx7wQOADbxcDNAQKA6wW1b79+UX0lJkoGXpTj4TbgBzUO/zsA\nPml57EsAnlDVLgBP1H6mnDGvCwucXxvWYA32rY6/p2RoNqGO4hVIwFfVpwCMWx6+GcB3a//+LoA/\nCGJflC4ru9oxo3j+YzajWKgHautEnW37RxoGiyxOqvIiKbNYGx0HL8rJFmanbYeqnqj9+3UA+fp2\nEoBqkH7gtmtsc/jW1iAAFuRykJS5BHEXp2P/gD+RjNJRVRUR284CEdkAYAMAdHZ2RnE4FDG3E6zW\nLV+EdcsXNewMTELQi0NS5hLEWZwuz+9/UMKspTMqIpcCQO3/J+1epKpbVLVXVXvb29miy5pGt/92\nKRq7glyGPOeHk5IqifM4kvL+B5laizpNF2YL/zEAnwXw1dr/d4S4L0ogNy0yL63BLE2g8iopcwni\nPI4kvP9B3mXEcccSSMAXke0AVgGYLyLHAXwZ1UD/AxH5UwAjAP4kiH1R8MLKiwadhkhK0ItLUmax\nxnUcSXj/g/xMx5GmCyTgq+qtDk/dGMT2KTxhtjLCaJElJehRPOJ+/4P8TMdxx8LSCjkXZisjCS0y\noiAF+ZmO4/vBgJ9zYbYyOISOsijIu4yo71gY8HMurFYGh9CRoVEtJYoWA37Omb+MQUrKuHGKl7WW\n0t7h09NqKVlfz7vC8DDg54TdF8nrl9GLJAyho/g51VKy+4xt6h/C5t3DKCsiuSvM450HA34OOKVX\nvHwZvWKHLQ2URnFs/F1cUBCcq1Qn2hcEmDOzzfa1m588jHJtPn7Yd4VhNnaSLMyZtpQQTjMUGxU2\nC0KjWbOUbUYjY9fQGAoiWDRvFgoAKgps3j2MTf1DU16/bf8IypXz1VeKglDvCptVcc0qBvwccJoO\nbxQ2W93djtXd7blo4VA0zI2Ms+UKZrYVYYTXsgJf33U+6FfTjaem/P7aqy4N9bPot7GTlMqlXjGl\n00RWOpGuu3wegOm5SrfDwpz6ALLwt6Hg2S2LOHxyuJ6yUQAP7BoGAEycmaynfAyHT05goDQa2ufK\nXMV17O2zaJ89w/XvBl1egePwEyILQwutKxCtW77I1zZ+OHgc61csQem1N7F3+DTOlivT/ja8EJBT\nH87Xdw3DHNo3P3kYGz9xBWYUC1NSLEOjb+Ou7c+H+p0ztnvX9udx8NUy9h0Zd7W/oEagxRFfmNJp\nwEt1vqTe4rk9h4HSKO548ADuePDAtHOwbuOBXcPYNXQ+B2rernVRk6T9PSg61j6cu9d24y9WL53y\nmnJFMXFmsp5avGzuzPpzUVTEtH62t+0fafo9DqpiaBzVPxnwG3D7xiY5yDU6B+Mital/CHc+/Bx2\nDY1h19AY7nz4uSnnYN6GHXP+s9UPcVIvmOSP9X29e2037ly9FAWpPj+jWMCcmW3Yc2gM65Yvwr2f\nuqrhdy7oz4n5sz2jWMDe4dNNv8dBrbwWR6npQBYxD0oSFzF3k55I+uLaTvl343ayKKjnVg3Wcxgo\njeK+/l9gaPTtadtf3d2OB+/42LTtul3EmgtfZ5PT+2oeEnlBQVAQwdlypf4aALbj48P6nBjfj2Pj\n72LX0PkGShTf46DSn1EvYp5Zxm0pgNSu42k3PNLcEi8r6i0uwH7EQl9PB9b0LEDR/EJgWr9AK62f\npCxsQcFyel/NQyLPVdQ2NbjvyDh2DY1NaWmH9Tkxvh/rli+K/Hsc9dBldtq6EPc6nmGwjqIwOmJP\nvf0bzJ99Yf11Rgtkzsw2bH36KMoVRVGqw+bmz55he75eC0JxVm42Ob2v5scLAAq1iVnGa5w6RcP+\nnKTxe+wVUzouJD1l0yrr7aT1lnn1lZeg/+AJlBXT0j5B/w04siebnN7XTf1D1Zm1FUUBQM9l78fn\nbuyy/RxyBFhzblM6obfwReRXACYAlAGcc3NQSZOmFqiXL4S1JW5tWT3+4on6c0bap6Lh3O7GvbAF\nhcPpfZ04M1mfWVsB8PKJt6b8jlNLO+2fk7gvWKG38GsBv1dVTzV7bVJb+ED8b5QT83EB8NWpNaUj\ntyBTproDwAUFwcqu+bkpNEXhGSiNYuP3Blu+a0zq97GRMAcnJKaFnxVJbFmYP0Dff2YEc9/X1nRC\nSKMvirllZeTsje0B1Q62hfMuStzfgdKnr6cDG1ctrad1vNw1tjJhKQkXiCSUDI8i4CuAnSJSBvBN\nVd0SwT5zwfwBqgAYf2ey/pzTGOZmXxTzhW3ZwrnYtn+kPqM26eksSpe713Zj2cK5ngOx18CZlBnz\nSUgNRxHwV6jqqyJyCYABEfmFqj5lPCkiGwBsAIDOzs4IDsc/p9ZC1K2IlV3teHjfyLQx9N0ds/GF\ntVdOOwavXxQj+CehdUTZ1Mqds9fAGVfL2vq9ScIooEhH6YjIvQDeVtX77J5Pcg7f0GgySRyThzb1\nD+Ebu4dhpNtnFAuOVS85wYmywksjJI7PfdT7TEQOX0TeB6CgqhO1f/9nAF8Jc59Bs36wnFoLcbUi\njNtip5V7rMcfdwuDKAhe7gzi+Ny7iQdx3DmHndLpAPCoiBj72qaqPw15n4Gxy/25mUwSdX7O6cPv\nlLtkoKe8ifpz3ywexNWvEGrAV9UjAD4a5j7CZFdJb+G8i7B+xRJMnJmccmVOYus5CaMCiJIo7NZ1\ns3gQ13eTwzIbMF+ljUp6Z8tjjjm5pLSezeUQZrUVI73rYAcvBSWMz5KxcLnTWg5RiSsjwNIKTcRZ\nSa+ZZlUwjRo51ruRMI+HncIUhDA+S+ZtmoXxXTbva0axgO4FszF/9oXTqn8GdUFLRKdtFpiHJu47\nMp6Y8gpOOUDrreLEmcnILkxMIVFQ7NKpfoOjeZuGogBzZra1tL1GAdu6pu+Lr1ZLR+wdPl0fRRdH\nRoDlkV1qpexvmJxKxUZdqtm8IEXSy0RTerSyMImXbVbr8FdrRG19+qjnbTZb9Mhp0aCz5Uqs5b/Z\nwvcgKTl6wD4HaLQ4okrj2N1lrF+xBDtLr2NNz4LE/K0ofcydnuZ0qp87x2bbBOD6LqLZ3ayxr+qd\nyan6Iu12a01EiQE/payjAAB/hdNaYXfbbaS9Xhk/imUL5zLoU8vCSKc6bfPU22ex8fvPolxRVx25\nbjpdzfsyz5MBqiXX4xjYwE7bmAQ9AiGOmv3mFn4BwNz3tU2p55OEjm3KhrBG7Bij2TbvHvZcubOV\nYwprYAOXOEywMBY9X9nVjhnF6tsZ1W1jX08H1q9YUq2Tj+bF24ha1dfjbylAu8XPjW1OnJmcEuyL\nBcGcmW1NF0tv5ZjiXs6TAT8GUb3pdh/yoE2cmUTFpnhbEjq2iQBvHaxFAdZ+ZAG2Pn000AaZ3b7i\naBQx4McgjDfdvDD02XIF2/aPBH4XYcd8ZwFU7y7sKnUSxaVZA8s8Am/jqqU4fHJiWt9UUOIe7cdO\n2xiEUYbB2okEIJIx8X09HXjgtmsci7cRxc1tBysA24lZe4dPY6A02rTmvnV96EYLDcX1HWGnrYM0\nlggIcrlDoixx8322Dnwwa9SJaze73VgtLqrvHmfa+uCnkl2cFwpryyFpxdyI4uKmVW2tnQXA1Upv\n1pTRztLriZ1xzoBvo9USAWGWPPVyy2hI0kQxoqSzm9vipsFkTRldcckcDI+943mt3igw4Ntwk/Oz\nC7h2E5GCKPhkre5nvmWMc41OoqyxNpLcfK/MF4o5M9uw9emjKFcURQHWr1iSqO8mA76NZp2qTi35\nlV3teOTAsfpoGTedPXbME0KMwG5I+i0jUR4ZF4p7dhysfzfLWh22nCQclumg0aQKp2FefT0duGHp\nxfXXtVIoyTxmePPu4WkjBma1FbGmZwGLlBHVRDHfxK24x9k3E3oLX0Q+CeD/ACgC+LaqfjXsfYat\nUcpn3fJFvup+mC8mZa3O+itXFAUBPvLB38JdN34YfT0dWLZwLjtkKffiWirQSRJXvjMLexHzIoAH\nAPQBOA7gZyLymKqWwthflCNkrrt8HoDp4879vuHWi8nqKy9B/8ETKCswfPKdQM+BKO2SuAZDkgdL\nhN3C/xiA4drathCRRwDcDCDwgB/Vld465taofmfm5w23XjD2HBqr1/kwp4+S1KohiktcSwWmVdg5\n/MsAHDP9fLz2WJ2IbBCRQREZHBtrvaZMVPVpotiPuf/ALicYdwEmoqRoVqogSfl9s7iOK/ZOW1Xd\noqq9qtrb3t761blZZ0lQf2DrSjzHxt91vc1N/UNY+7Unsal/yPX+7D7QSe8YIoqS0wCLMKrSBiHO\n4wo7pfMqgIWmnz9UeyxwjXLnQaZ7zCvZ7B0+jV1DY9h3ZLzpNjf1D+GBXcMAgKHR6v/vXts95Rjd\n1t5IescQURys36Ek5veBePsdwg74PwPQJSJLUA30nwawLqydOeXOg/4DGx+ms+XzS6Q1m2S1s/T6\ntJ+NkTbm8fbNLkjmDzUXFyGqsmvUJTW/H+dxhZrSUdVzAP4SQD+AlwH8QFVfCnOfdsJIgVjLAhuT\nrJys6Vkw5ecrLpljO96+UU4+qbeoRHFzatRFXYrYTeo4zhLJoY/DV9XHATwe9n4aCSMFYkyyMhZC\nNiZZOW3bSN8YC3xPnJmcMt5eACgaX5CSeotKFDenVnOUQyS9pI7jGrqZm9IKYfyBvU6yunttdz3w\nV2vkvFJfzV4B/PZl5ydW2UnqLSpR3MLs13I7vycNDbLcBPww+PmQ9fV0oOO3LsSrvz5Tf+zsuUrD\nbbCzlshZGI06L632NDTIGPB98vMh+4OrP1QfuQNMz/MHvT8i8sZLqz0NDTIG/BhZ8/rmYZpE5E8Q\npVa8tNrTsEpe7pY4TMObQkT+WEug+BkN4yZmBLm/Vrhd4jD2mbZR4rBGouyxGwoZZPmRRqXSw9hf\nmHIV8NPyphCRO3aNuIHSKJ575dcoSPU1QXSgNhtfn5ZyJ7nK4aehF52I3LNbVtRYDhSotmj9LjPo\nZqROGjpsgZwF/LS8KUTkjrURB6Ae7AGgAv/LDG7bPzLlonJf/y8ATF/vNg0j6HIV8IHo3hR2DhOF\nz9qIAzClhT+jWPB1Jz9QGsXe4dNTHhsafRt3bX8+letQ5C7gRyFpy64RZZm1EffAbddg2/4RANNX\npPOqWiSxMu3xpM6kbYYBPwRpmGJNlFVB3sWbU0ZGscSz5Upq+wAZ8G34Tcewc5goG+xSRmlO1eZu\n4lUzQU2gaPWiwdw/EXnlduIVW/gWQaVjWrmtZO6fiMKUuYlXfteujXMCBSeGEVGYQgv4InKviLwq\nIi/U/rsprH0ZgiidEOdqNGmZrUdE6RR2SudrqnpfyPuoizMdEwRODCOiMGUqh5/U0TFeOmLTMFuP\niNIptFE6InIvgDsAvAlgEMDnVfUNm9dtALABADo7O68dGRnxtd+kjXKJu2wqEWVfJOWRRWSniBy0\n+e9mAN8AcDmAZQBOAPifdttQ1S2q2quqve3t/lvkbkqZRokdsUSUFL5SOqq6xs3rRORbAH7iZ19h\nCvOuIKlpJiLKn9By+CJyqaqeqP14C4CDYe3Lj7DHvrMjlijbkpZGbiTMTtv/ISLLACiAXwH4sxD3\n1bIo6t6wI5Yom9I2WTK0cfiq+hlV/W1V/R1V/ZSptR8LpwlZHPtORK1KWx9dpoZlOml0FWbKhYha\nlbY+ulwE/GZpmzBTLmnK7xGRN2lrMOYi4Hu5CgcZoNOW3yMi79LUR5eLgO/2Khx0gOZCKESUJJmr\nlunEzYSsoDtg2CFMREmSixa+lVPaJugOmLTl94go23K34lWz2jbsZCWitOGKVw7iHLFDRBSn3OTw\nDcyrE1Fe5a6Fz7w6EeVV7gI+wLQNEeVT7lI6RER5xYBPRJQTuUzpOOGQTCLKMrbwa4zx+Q89M4K7\ntj8/rYwyEVHaMeDXpK2uNRGRV34XMf9jEXlJRCoi0mt57r+JyLCIDInIWn+H6Y3TYieNXjtnZhvH\n5xNRpvnN4R8E8IcAvml+UER6AHwawEcAfBDAThH5sKqWfe6vKS8VL61lFtavWIKJM5PM4RNRJvlq\n4avqy6o6ZPPUzQAeUdXfqOpRAMMAPuZnX255Sc1YXztxZrJpRU0iorQKK4d/GYBjpp+P1x4LnZfS\nCSyzQER50jSlIyI7ASyweepvVHWH3wMQkQ0ANgBAZ2en3815Kp3AMgtElCdNA76qrmlhu68CWGj6\n+UO1x+y2vwXAFqBaHrmFfU3jpXQCyywQUV6EldJ5DMCnReRCEVkCoAvAgZD2RURELvgdlnmLiBwH\ncD2AfxGRfgBQ1ZcA/ABACcBPAdwZxQgdIiJy5mtYpqo+CuBRh+f+DsDf+dk+EREFhzNtiYhyIvPF\n01gQjYioKtMtfBZEIyI6L9MBnwXRiIjOy3TA50xaIqLzMp3D50xaIqLzMh3wAc6kJSIyZDqlQ0RE\n5zHgExHlBAM+EVFOMOATEeUEAz4RUU4w4BMR5QQDPhFRTjDgExHlBAM+EVFO+F3x6o9F5CURqYhI\nr+nxxSLUtP8SAAAFaklEQVTynoi8UPtvs/9DJSIiP/yWVjgI4A8BfNPmucOquszn9omIKCB+lzh8\nGQBEJJijISKi0ISZw19SS+c8KSIrQ9wPERG50LSFLyI7ASyweepvVHWHw6+dANCpqqdF5FoA/yQi\nH1HVt2y2vwHABgDo7Ox0f+RERORJ04Cvqmu8blRVfwPgN7V/PysihwF8GMCgzWu3ANgCAL29vep1\nX0RE5E4oKR0RaReRYu3flwPoAnAkjH0REZE7fodl3iIixwFcD+BfRKS/9tTHAfxcRF4A8I8ANqrq\nuL9DJSIiP/yO0nkUwKM2j/8IwI/8bJuIiILFmbZERDmR+TVtGxkojXKBcyLKjdwG/E39Q9i8exhl\nBX44eBz333o1gz4RZVouUzoDpVFsfvIwyrVBoO9NlrHn0Fi8B0VEFLJcBvw9h8ZQrpwf8l8UYGVX\ne4xHREQUvlwG/JVd7ZjVVgQAFAuCjauWMp1DRJmXyxx+X08H7r/1anbYElGu5DLgA9Wgz0BPRHmS\ny5QOEVEeMeATEeUEAz4RUU4w4BMR5QQDPhFRTjDgExHlhKgmZ5EpERkDMOJjE/MBnArocNIib+ec\nt/MF8nfOPF/vFqlq03IBiQr4fonIoKr2xn0cUcrbOeftfIH8nTPPNzxM6RAR5QQDPhFRTmQt4G+J\n+wBikLdzztv5Avk7Z55vSDKVwyciImdZa+ETEZGDVAZ8EfmkiAyJyLCIfMnmeRGR+2vP/1xEronj\nOIPi4nxvq53niyLybyLy0TiOM0jNztn0uv8oIudE5I+iPL6guTlfEVklIi+IyEsi8mTUxxg0F5/r\n94vIP4vIv9fO+Y44jjMoIrJVRE6KyEGH58OPW6qaqv8AFAEcBnA5gBkA/h1Aj+U1NwH4VwAC4DoA\n++M+7pDP9z8B+EDt37+X5vN1e86m1/0/AI8D+KO4jzvk93gugBKAztrPl8R93BGc818D+O+1f7cD\nGAcwI+5j93HOHwdwDYCDDs+HHrfS2ML/GIBhVT2iqmcBPALgZstrbgbwkFbtAzBXRC6N+kAD0vR8\nVfXfVPWN2o/7AHwo4mMMmpv3GAD+CsCPAJyM8uBC4OZ81wH4saq+AgCqmodzVgBzREQAzEY14J+L\n9jCDo6pPoXoOTkKPW2kM+JcBOGb6+XjtMa+vSQuv5/KnqLYS0qzpOYvIZQBuAfCNCI8rLG7e4w8D\n+ICI7BaRZ0Xk9siOLhxuzvnvAfwHAK8BeBHA51S1Es3hxSL0uJXbFa+ySERWoxrwV8R9LBH43wC+\nqKqVagMw8y4AcC2AGwHMAvCMiOxT1V/Ge1ihWgvgBQC/C+AKAAMiskdV34r3sNIrjQH/VQALTT9/\nqPaY19ekhatzEZHfAfBtAL+nqqcjOrawuDnnXgCP1IL9fAA3icg5Vf2naA4xUG7O9ziA06r6DoB3\nROQpAB8FkNaA7+ac7wDwVa0muIdF5CiAKwEciOYQIxd63EpjSudnALpEZImIzADwaQCPWV7zGIDb\na73e1wF4U1VPRH2gAWl6viLSCeDHAD6TkRZf03NW1SWqulhVFwP4RwB/kdJgD7j7TO8AsEJELhCR\niwAsB/ByxMcZJDfn/AqqdzQQkQ4A3QCORHqU0Qo9bqWuha+q50TkLwH0o9rTv1VVXxKRjbXnN6M6\nauMmAMMA3kW1pZBKLs/3HgAXA/h6rcV7TlNcfMrlOWeGm/NV1ZdF5KcAfg6gAuDbqmo7vC8NXL7H\nfwvgOyLyIqojV76oqqmtoiki2wGsAjBfRI4D+DKANiC6uMWZtkREOZHGlA4REbWAAZ+IKCcY8ImI\ncoIBn4goJxjwiYhyggGfiCgnGPCJiHKCAZ+IKCf+Pyz6tB+8T5W+AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x11ee667b8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "m1 = plt.scatter(X_train, y_train, s=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x11f2297b8>"
      ]
     },
     "execution_count": 136,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAD8CAYAAAB0IB+mAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3X94VOWZ8PHvPUNCQqVaMQZ/EKGYBlPRSBB/ESuaqHV9\n10qrLXDVXekltT/U7rW1dttetmu3fbtLuyrW6mJfrbYG6y+W4qo4sSABBQyaCkYjQQuoEAJ0FSUh\nYeZ5/5g5w2Qyk5nJnDNnZs79uS4vyWQy5znJzH2ecz/Pcz9ijEEppVTx87ndAKWUUrmhAV8ppTxC\nA75SSnmEBnyllPIIDfhKKeURGvCVUsojNOArpZRHaMBXSimP0ICvlFIeMcrtBsQ65phjzMSJE91u\nhlJKFZSNGzfuMcZUpHpeXgX8iRMn0tbW5nYzlFKqoIjItnSepykdpZTyCA34SinlERrwlVLKIzTg\nK6WUR2jAV0opj9CAr5RSHqEBXymlPEIDvlJKeUReLbxSStmrPdBMX2cLZTWN1DXNdbs5ymUa8JWK\nEejopnVLDw3VFTTVVrrdnKy0B5qpWXMT5dJPb89y2kGDvsdpSkepiEBHNzcueZWHXtrGjUteJdDR\n7XaTstLX2UK59ANQLv30dba43CLlNg34SkW0bumhdyAIQO9AkNYtPS63KDtlNY30mlIAek0pZTWN\nLrdIuU1TOkpFNFRX8Fjbu/QOBCkv8dNQnbL4YF6ra5pLO2gOX0WJMcbtNkRNnz7daLVM5aZiyuEr\n7xCRjcaY6amepz18pWI01VZqoFdFSwO+UjG0h6+KmQ7aKhVRbLN0lIqnAV+piGKbpaNUvKwDvohM\nEJGVItIhIq+LyE2Rx48WkYCIbIn8/1PZN1cp5zRUV1Be4gdwZJZOoKObhx+6h557/x7+cBW8+bSt\nr69UKlnP0hGR44DjjDGviMhYYCPwBeAfgX3GmF+IyPeBTxljbhnutXSWjnKbUzn8QEc3S5fcx+2+\n2xkth8IP+kvhqgdhymW2HUd5U85m6RhjdgI7I//eLyJvACcAVwAXRJ72ILAKGDbgK5VILgdSnZil\nE+joZs1TD3KDPHI42AME+9n+8lNUacBXOWJrDl9EJgJnAOuBysjFAGAXoFMeVMYKfSDV6tnf8vFC\nTvHtIPaG+qAZxS/eOr7gzkkVLtsCvogcATwBfMcY82Hs90w4b5QwdyQiC0SkTUTaenp0kEwNVugD\nqa1bephh/sKYSE0bEejxHcvzwTq+NXATTw+cUXDnpAqXLQFfREoIB/uHjTFPRh7ujuT3rTz/7kQ/\na4xZbIyZboyZXlFR2EvZlf1iB1Iv9m/kC+/fUVCDnQ3VFWyQ0zkQqWlzUEbTWv09vs2/0BKqL4oS\nDqpw2DFoK4Rz9PuMMd+JeXwhsDdm0PZoY8z3hnstHbRViSxc0cmW1X/kjlF3MUb6CfrL8F/1AEy5\njEBHNyUv/BszPmxhzFHHwuduyXoQNNDRze62J2mQTVSdebktr9excglH73qRF4KnstY/g/kzJ7G/\nb0AXeClb5LK0wnnAV4FNItIeeewHwC+AR0Xka8A24GobjqU8aH/fAOfKpmhaxB/sg61/JhCqp2vJ\nLVzvW4oI0Ps+PPpVuPr3Iw7SVs79l747wxeXvz4RvbiMVFNtJa1bGrl9R3X4gVCQ/X0D3HbFqSN+\nTTvp6mLvyDqlY4xZY4wRY8xpxpi6yH9PG2P2GmMuMsZUG2MajTH77Giw8p74tEjQXwaTL6R1Sw8X\nSFs42FtCh2Drn0d8rPicu3VxyVayOf6Bjm5uXbbZtYHb2EHxbz38Ctc+sEEHkYuY1tJRea+pthLm\nXMfStnGD0iwNoW5WtU1nitlxOOj7RsHkC0d8rIbqCpa2nc7VZtXh9FEWrxd7DovmnDGoJ20F296B\nILs2PMm4E7czbdbsnM7Ljx0U7w+GWNnZw7q397Fozhna2y9CWh5ZFbR8yeGPZO/YW5dt5qGXttHo\n28iikqHjE7kQe9GJdc05J+VNykmlpuWRlSc01VZC7V22vFZsLnveNd9I++dGundsQ3UFD6/bxkzf\n0PGJXAX8ptpK5s+cxD0ruwhFHiv1+3TmUJHS4mlKkd0Cr5HuHdtUW8n1F5zMi2bqoPGJ9tJpOc3r\n7+8biAZ7gPNOHqfpnCKlPXylSLzAK92gV1bTSG/P8nAPP8O9Y+smHEXHyZdy34FPcuUn32Lf+JnM\nWX00vQPbcpbXj9/ace5ZJzl2LOUuDfhKkd1+tiPdO3bhik7uXdVF0MC6kinUzpoTufCE8/p3jLqL\nMd39BB9b7mheP9GAsipOGvCVp1h5+rFlJYMWPg0X9NKZp17XNBcy2CQ80NHNvS9sJRiZM2HdVTRU\nV/Dw+u0jyutnM59et3b0Bg34yjMSzUh5rO3d6BTEREEv9mdin5vJMRMF4dYtPQRDh2fI+YXoc67/\n3GReXD01o6mh2bZTeYMO2ipXuLHgKDZPb0lVkC2b4m3DDQTHLsTy+4TrLzg5GqBvvqSGq+Z9naWT\nb2P75HlppXPi29m8fhsPP3QP23//zYKqPaScpT18lXNu9UZj8/QWK1+frCeeTW5/uIHgVHnz8HTT\n8NTQQEc3rcs2D5uqiW1nqd/H6K0ruNK/KOPyEIGObprXbwNg7lkn6V1CkdGAr3Iumxkxw0m1YCo2\nyMbm8IGEFyDrIjB/5iQ63v8g4/akulikkzdP9+IYe2479h3g7K2vjWgM4FsPv0J/MDxJc23XXu6e\nN02DfhHRgK9yLptec6zYXjmQVtGzREH22gc2JEzbWIG21B/OfPYHQwnLDiS7O7Bj9kvz+m1pXxyt\nc1u4opMXu5KPAQw3rmAFe+t87boYq/ygAV/lnB2BML7ne/anj+ZziYqepdGrXdu1N/q1tco0vsaM\nJT7oLlzRGZ5tEzI8smEH3zq+kys/+Vb0DiOb2S/J2maVk6jvXcfY0/8PXHTroJ+5f8079Abr+Q43\ncH3cPP7h7hgaqit4ZMOO6PnqitviowFfuSLbaYDxaSGADZJZ0bP2QDMHXn6K880UWqgHBq8yjc2J\nQzjwx1e6tObRA5xvXua63Xcxpqefvq2P89wnZ1NX4cu4pr7VA9+x78Cgi815J48DGFQS2rT+CoFo\n0I/9vTwXrGf88bOZNuVwTZxU4wp3z5umOfwipgFfFaSEq0PPGlpRMxmr/k2d9NNUEuDGgRtY658R\nXWUafxcCDKl0+csVb0aDPTBo7nwZB7nsgz8y6sMQA+88QcnV6Q+axqaSSv2+6IVm7lkn0bqlhzkx\nJaEFoPOZaMBPlS6zY1xBFS4N+KogJU0L1aZX9Cy2/s0Y6efS8g6+/MWvD8nBx38Niefz+4CXzOG8\n+YDxUSLh3nlJqI/tLz9FVRoBPz6VNKumgglHjxl0jrEloQ0gNZ9P/XuJ+f78mZP46C/LuGLsW0zz\nhYDclWNW7rIl4IvI/cDlwG5jzKmRx34CXAdYE5d/YIzRCcHKNtn0RmPr3xwwpbQc/CxfTPNnE83n\n/8ask6mbMJ37Vn6ST+1aywehcr426hnGRF6/1UxlXhqvnejOZchFZ86/88ILY6n9cC3dpVUc+f4u\nqt58mkCoPmU6JtDRzTtrHgsPbh9wvmyDyi929fB/B/waeCju8duNMb+06RhK2aauaS53vrWbI3eu\nZU1oKi2haRybYEZKohktVvmD2JWy+/sGIheg7xDomMNjz7/Fa7tO5jzZxAY5nSunz07ZJmta6cPH\nb+SNT9Rz7PTZSadgBvgRP7FmJX3Qz8A7T/BE/7dZeWgakHxKZdIdvTTge4ItAd8Ys1pEJtrxWkrl\nSu2sOdy4ZAq9ocT57GQzWqzyB9aAbfzPWs8JdHyG1i09XJnGTKT4vXRP9y/HP+MkkqVb4gN3SaiP\ns3mNZwkH/GRTKkeyo5fueVs8nM7h3yAi1wBtwD8bY/7m8PGUSluqfPdwM1puvqSGuglHDRsIM0k5\nZdrzjg/cA74y1nFa9PvJplQm2y4ymfiL3vyZkwYVnVOFxbYtDiM9/KdicviVwB7C40o/BY4zxsxP\n8HMLgAUAVVVV9du2bbOlPUplK3blaanf5+iq0/gefjpbHVopoFM+3siHlPNJemkNnUr7mHOH5PCH\n66UP9z1rG0aL3ycEQ4byEn/CVb96N+AO17c4NMZEK0WJyH3AU0metxhYDOE9bZ1qj1L5HIxS9bwT\ntT2cy5/Nb5fsHZwKuugBmDJj0M8mW2yV7HvtgWbKX3uIb4T+xoWl5fzh0IWsNPXRcYtEq361Ymf+\ncyzgi8hxxpidkS+vBDY7dSylUondbCTdYBRbaiAXZQZiC6bFGi6QppMKSpaaCnR0s+apB7nFvMwa\n31RaBupp3dJDxXvPc8qaGxgthwA4zgfnlW5iec0v+GHHhKRz+J2qkaTsY0t5ZBFZArwE1IjIuyLy\nNeA/RGSTiLwGzAL+yY5jKZWpZJuNpBJbwji2quaqe25g/3+eCc/f5mSzo4Yr0dxQXcEGOX3QnrjE\nDcImO4+lS+7jlo8X8o+jnmNRyV1cVvIqDdUV9HW2RIO9pYRDzP5kJ4vmnME155yU8II5tqwEf2RB\nWDY1kpRz7JqlMyfBw//PjtdWaiSs/PbFB57hlA92sdhfzhIuoiVUH91sJJX4Qd32Hf/LmNaf8U3/\nsoRlDZwy3OrYdAZhEw1O37ps86A7gzHSz/c/8z5VtZW0v9fIwZ5lg4O+vxQmX0jTlMQD0VYNn6AJ\n5/nnz5ykvfs8pCttVdGxeq+3+26PBq0T/TDTt5kbDt1E9flfTjsYHZ5iGa6b81TJK0nLGjglk9r5\nw70GwO62J9m+cROzx89kcVztoaozLwcO79Fb/tpDjPd/yJHHnADTr006gDwkNRSqZ3/fQPYnrmyn\nAV85LteDpVZeOz4tMVoO8aMpu6i6pGZErxk00BKcxhRJXNbASdnWuImfBXTCX59gwfm3s3TnbQnv\nDNLdo3fQ647q52qziu+GbqKhOuWEEeUCDfjKUW7M3LDmqM8xfx6Slqg68/IRXYCstMqvBr6MT+Cq\nsZs5dvoXHO/d2yXR4G5d/yvUXZPdQvj4141NDan8owFfOSqbmRvtgWbKNz3E0WNKqbjg+kE13VMt\neGLOdTzeNo6LDzxDhXwAnzgWpl9LIFQ/ogtQbFrlM9ULObbAAtpIVtimEujoZvrWXzPN9woDxk+J\nBAelhlT+0YCvHDXS3a3aA82HpwZ+CMFHX8R/9UNpB+zDee3Bue3WZZtHfAEq5NLBma6wTSXQ0X24\nLr8vnN764KjPcuSlP9K6PHlMA75y1Eh3t4qfGugPDcDWP9N6qCplwG4PNNPX2UJZTWM4Fx3Dru0V\nC1E6g7vDif29th44bUhd/iNLjQb7PKcBXzkuWc94uNRMWc3gqYFBXwn+yRfSEDocsP0+YWxZyaCf\nszY2KZd+enuW0w6Dgr4d2yt6UfzvtW7Kz1llktflV/lJA75yRarB3OjUwLgcfhMwf+ak8KrZkOH+\nNe9QN+Go6M/GbmxSLv30dbYMmW1SiKkZt8tCxP9ej9/7EmMjdfkT7a2r8pMGfOWKVIO5gY5uWg+c\nRsOlD1ITF+D29w0MWTVr/Wzsxia9ppSymsbcnJCDYi+Oj2zYwXknj8v5frOJfq9n11ZC7V1D2qp3\nT/lLA75yxXC59FS9/+F+1rozSJbDL0Tx2x6u7Oxh3dv7clqcLJ3fqxZPy38a8JUrhsulp+r9p8rD\nJ1o0VMg9z9gLnCWTGUZ2nXuqxVhaPC3/acBXrkmWS09nJk0mefhC73laF7jm9dtY27WX/mAo7RlG\ndp17/EUj2daPXp0BVSg04CvXWYXOrPnhTbWX2TqTphh6nrE1fTL5vdhx7ol2vbp/zTsJt37UGVD5\nTQO+ctWQnZ7++gT+qx6gqfYy2wJGMfU8M51hZMe5x180Wjp2Jb2IFOIMKC/RgK9cleleriPJR3u5\n52nHucdfNBprx7N93ztFcQH1Gtv2tLXD9OnTTVtbm9vNUDYLdHTTvH4bdQdeZK7/z+HaNgCfOJb2\nyitZvPrttPZyjU0tJNtTVTkjnRx+7HNjU3S6+tZ56e5pa0vAF5H7gcuB3TGbmB8N/BGYCPwVuNoY\n87fhXkcDfvGxNgI/37zM3SV3DilZjL+U9rPv5PWdH9Agm9g3fmb03/HBIn5D7WvOOYnbrjg1V6ei\n0jCSzdhV9tIN+LZscQj8Drg07rHvA88bY6qB5yNfK4+x9oWd6ds0NNgDBMOrYY+dPpvO+h+zePXb\nXLn1Vqq2PkzwsWvhzaejT020VZ/KL0lTdCov2BLwjTGrgX1xD18BPBj594PAF+w4liosDdUVlPp9\nrAlN5aAZOmR00Izit+9P5MYlr9K8ftuwwcLKRyfbU7XYBTq6uXXZZgId3XnbjnT22FXucXLQttIY\nszPy712Atz6dCggH6bvnTaN5/TjuPfDJQTn8zo/LWbjnXFpC9RAKz/rYIPbWbC8W+bKWIFU77C7D\nnOj4Xhx8t0tOZukYY4yIJBwsEJEFwAKAqqqqXDRH5djhqXozgO9EH9/e0c3aJa9CKDwIO/esk+Cs\n5MEiX4KeG/JlLUE67ci2DHMyXv7728XJgN8tIscZY3aKyHHA7kRPMsYsBhZDeNDWwfYoFwzXI0s6\nZTBJsMiXoOeGfFlL4GY78uXvb+ddRq7vWJwM+H8C/gH4ReT/yxw8lspD6fTIMlmoky9Bzw35spbA\nzXbkw9/fzrsMN+5YbAn4IrIEuAA4RkTeBX5MONA/KiJfA7YBV9txLGU/p3oZdvfI8iXouSVfVrG6\n1Y58+Pvb+Z52447FloBvjJmT5FsX2fH6yjlO9jKc6JHlS9BT7nD772/ne9qNOxYtreBxTvYy8qFH\nppSd7HxPu/H50IDvcU72MnQKnSpGdt5l5PqORQO+xznVy9ApdMpi1VICcr41oxpMA77HxX4Y7ZQv\nU+iUu6xaSv3BEABru/Zy97xpSd8LelfoLA34HmFVMLz4wDNUHDEapl9LIFSf0YcxE/kwhU65z6ql\nZOkPhpJe/Beu6OTeVV0EDTm5K/TinYcGfA+wKhje7rv9cAGzd1ax+6Tb6A8eXt083IcxUzpgqwId\n3ezYd4BRPuFQKLym0icwtqwk4XPvfWErwcjSS6fvCjO98ygWGvA9wKpgOKhaZbCfBtlEqX9i9E1f\n6vfZ2hN3ewqdck/sGE6p38dJR5exY18vIQP3ruoC4OZLaqLPb16/jWDo8EJ7v+DoXWEmdx7FxK7y\nyCqPWRUMB1Wr9JdSdebl3D1vGrNqKphVU+GJHo7KjdgxnP5giLISP1Z4DRr4zcouFq7oBKy8/Z5B\nP3/Jqcc5+l60qrhaMu3s5Evl0kxpDz+FYtm9p/fTF3PvgSPC1SojOXymXEYTpPXBSjSY1h5opq+z\nhbKaRuqa5jp8BqqQJNoWsWt3VzRlY4C7V4Z7+vv7BqIpH8vW3fsJdHQ7FvQPV3HdRs9H/VQcUZr2\nz9pdXkHn4eeJZBtsF1LQj31zriuZQu2cORm/seLf4PNnTqK06xkW7P4Z5dJPb89y2iEa9IvlIqlG\nLtkYzm9WdhEb2u99YSvXf24ypX7foBRLZ/dH3LjkVUcHbq3XvXHJq2x+L8i6t/eldTy7ZqC5MXVZ\nUzrDyGT3nvZAM+t+PZ/2QHMum5hSojdnIoGObq59YAPXPrBhyG1q/GvcvbKLI3eupTzyeymX8K5V\n1ussXXJf0l2rlHc01VZy2xWnRoPYzZfU8M1ZJw96TjBk2N83EE0tnnBUWfR7w71f7RL/3m5evy1l\nqsaundfS/WzaSXv4w2iormBpW+oNOdoDzdSsuSlhb9dtw02PtG4nx5aVcN/qt5POWIh9Dcua0NTo\n76XXlFJW0wgMc5FM0cvXu4LiFP93vfmS8N/1nlVdhEw4dz62rITWLT3h/RBg0Eb18cHU7vdJ7Hu7\n1O9jbdde+oM9w/a47ZqB5sbUZVs2MbdLPm5ins4bbN2v53P2nicOf33MFzn72/fnspnDSpQnjL2d\n9AvR3KolfoPwQEc3v1zxJp3dH0Ufa/RtZKZvEx8cdx43fes70edluom1bnxdnJL9XWPXf4zyCT4R\n+oMhykv8LJpzBkDC+fFOvU+sz8eOfQdY2Xm4lx3/GXCCXTn8dDcx1x5+CtbuPYGObn7b2UNDaOhA\nUllNI709y8M9/Jjebr5IND0y9nYyaMLzo61xs0QzFppqK9n/lz/x0b7nWB2cSkuonpZQPWv9M1g0\n64xBz8t0i7uR3hWo/Jbs79p6qCp6NxkerA2/8ay0RkN1Beve3hced4rJqzv1PrE+H4GO7uhxc9Xj\n1lo6eSjV4Epd01zaoaBmrMTfTs6fOYmO9z9gz0cHafRtZMZzP4UVH/L2cX/H78q/St2Bl/j8mz+g\n3N/Pl3yrePD4W9k5flbSnawy2eIu3dSZKizJ/q4NocPvPR/giyzMsoJsskFRp98nXlgsqAE/DemM\nytc1zYUCCPSWRG9u65b5m75fUSLhHtik/72XikM7+Uh6KR8V7lmNkX7OGHiVb1xxg21tcXLja+WO\nZH/XJmD+zEnhlbUhAyHDqSccyU0XVUc/V4ly27l4nxT7YkHHA76I/BXYDwSBQ+nkmfJNIdWFySQn\nGP/mtm6ZrWAPIAKN/lf41aGr+VKCQVq7OLXxtXJXsr/r/r6B6MraEPDGzg8H/Uyynnahv0/cLg6X\nqx7+LGPMntRPy0/5fKsX+wYCsprXa90yzzMt0aBvDLQEp9ESquefDt3AVZ/q4pjTLy2ItJXKXw3V\nFTy8blt0skAwZAbdOafqaScqBpjvd4X5UDJcUzppysdbvdg30B9e2sZRnyhJmXoa7oNi3TI/2jaO\nC3f9juDHe1h66Dx+FfwyACuC9VRWz+a2JmdnLqji11RbyfUXnBxN62Ry55ysGCBXPZg06OfDtN98\nKBmei4BvgBYRCQL/ZYxZnINjuiLXt2uxb6AQsO/jgej3ks1hTvVBOXzLHJ6Z9Mr6bZR27Y1Om8vn\ndJYqLDdfUkPdhKMy/swkKwaYbMaOWyvm4y8yDdX1rqeGcxHwZxpj3hORY4GAiLxpjFltfVNEFgAL\nAKqqqpK9Rl5JNa89V7dr8bfFlprKI/juJVMSTsXM5IMSO10tH9NZqvCN5M7ZSj3OMX8+/F72l0KS\nGTtuTPtNdJFpuuoBFs2pd/Wz5HhpBWPMe5H/7waWAjPivr/YGDPdGDO9oiL/eo/xVfGswP7QS9u4\nccmr0cfdWCZt3Rb75PBjpX7foGAf2/5kVTOTfVBijxO7RF4pNzXVVnLlnOt4fPK/0TP+c3DyxcOm\nc6z3/QETLpAW9JelfM9nK9lFJvaz5EbFTUd7+CLyCcBnjNkf+ffFwG1OHtNOiXrtw80RduN2zbot\nTrYyMb79V865jsfbxhXUYJdS8WJTj2k9N8fTflOtGXBrANfplE4lsFRErGM1G2OedfiYtkkU3JMF\ndjdn8iS7LU7U/tuuODXtD4pSxSLX0zlTXWTcGsB1NOAbY94GTnfyGE6KD+5jy0rY3fYkDx+/kTc+\nUc+x02cPmSOcD2kPa7DoCx9vZE/JRJ4eOEMHXFXBaQ80U77pIcb7PuTIY06w9W40V+NSnUc2cGz1\nbKqmDD6GWxkBLZ6WQmxFyXfWPJb3Bb7iB4sGfGU8OvEnQy5OTh5fB3hVttoDzZyy5obBEwz8pcPm\n6tMR6OimY+USjt71Ii8ETw3XgnIgnRK/xeN5J48bslG6nZ8VLZ5mE6vXfuuyzXlX4CvRGyZ+sKgk\n1Me8cVshR8He7YUlqjj0dbYMDvYAwX72P/1jxsKIPneDOkP+fr7oW8mNAzfQuuVE29+n8Vs8ruzs\noaTrWT59zDomV3wCpl9LU+1lOf986AYoaXJjpH84yWYLudlON2YqqeJUVtM4eDYZ4VXfYz98a8Sb\n6sR3hsZIP+f7NjG2rGREbQx0dPPwQ/ew/fffHNKe2E1SIFxK/K5RdzL5g7XQ9Rw89g+ubAykPfw0\n5VuBr2TBtXVLD5NmXsXS7ty0M/Yuo5BqDqn8ZlWgLd/0ECW9eyg5uI8Jvr3AyO+u42fOHDClrA5N\nZe2ad6ibcFRGve1Ui7msSRzN67fxwls9zPRtSnv9i5M04Gcgnwo3JRpQjt0paNGc2VQ53NZEKZz5\nMyfR0rGLxtrxms5RWbEq0EaDq7kzq7LIsZ22yt0v8ci+k2kJ1UMovLVhoqnNyaSzmMtKBy9c0cmL\nq6cOWih2SErYXDqNuozPIjsa8AtU/DRQN6Z5xR9z0fNv0bX7Y3oHgmzfl3mvSalE7Ly7Pryh0WzW\nLnkVQuFB1dYteyKbsQzd4jORTGrz33xJDYEJX+fxtgrO3rucHX87wB8OXcja1Uez6IShGyo5SQO+\nS+wYoY+fBprrdEpDdQWPbNgR3b2ocudKvujbxBrfVFoG6l0pDqWKU7Z31/Gft9gOU/zWhv3BUMr3\nbqYXIav9ty5r4KGXwncShHJfQE0DvgucmM3SVFs5JJ3idIXAptpKzjt5HCs7e2j0bWRRyV2MkX6u\nNqv4bugmGqoLbusDVYSSfd5ia0WtjRQIhMMbq9+6bPOwHbKRXITcHufSgO8CJ9IvgY5u7l/zTjSd\nAgxeN+BQhcC5Z53E6i17mOnbNGj2w/c/8z5V2rtXeSDV562ptpK7502jef029nx0kBn96xm/5gE6\ng6fy2AYYd+J2ps2abctnx+29NTTgu8CJq3z8m7qlYxdzcrBuoKm2kus/N5kXV08dlM+sOvNyW4+j\n1Eil83mzAu/SJffxz5F5+lf7ngdgdPchgo8tH7bD1B5oHrSn9XApWzdX5GvAd4ETV/n4N3Vj7Xg2\nrMnNxuDWoNTStoq8mLKqVKx0P2/xM29ip1EO12FqDzRTs+YmyqWf3p7lPLnnY37YMSEvFyBqwE9i\npPnvdAdj7b7KJ3pTBybkbt1APk1ZVSpeOp+3+Jk31sKv0XJo2A5TX2cL5ZGLRLn0439nJb0D8wD3\ndrZKRgN+AiPdIcfJ0gLpXIDi39QahJVKX/zMm33jZ/L6zg9SdpjKahrp7Vke7uGbUoKTZlHe4c/L\nBYga8BN77FQUAAAQJ0lEQVQY6Q45sXn084IbkKebwfeVrIs9Na/fxuitK/hP/6LoBWjT2bfz5IHT\ntEiZUjaK7SRVQVoLo6xVwVYOf+wJF3F2X/qLuHJJa+kkkE49mkS71TRUV1Dq90WnKDZ+tGxEdT+s\nGh1dd1xGySNfxr/lWc7mtUEXoM2t/z2kjo5Syh11TXM5+9v303PCRdy45FVWdvaw7u19bjdrCA34\nCVhbqC2dfBvbJ88bks5JVrjMmpceO0UxeneQJiud9KWtP+Lk/13LBb5XubvkTvab8ugF6KCMZtWh\nUwEtUqaUG1sFJpPvBQQdD/gicqmIdIpIl4h83+nj2aWptpJ513yDqq/+ZkhKZrg/6tyzTsqqWmWi\njcZHyyEa/a+wfMwX2D55Hm+cewdr/eGtgfMtR6hULiXrfLkltkpmPn42nd7T1g/cDTQB7wIvi8if\njDEdThwvV5tvjC0rwe8TgiEz5I+abd0Pa6ZAbKElY+AU3w4mHuimc/yd1DXNZX6oU4uUKc9za6vA\nZNxeWJWK04O2M4CuyFaHiMgjwBWA7QE/V5tvWCtagyGDX2D+zEkJF1aMdHaMdcGwNhoftbeTTw3s\nAsJTvvo6WwiccNGgVbVapEx5ldulChLJl61OE3E64J8A7Ij5+l3gLCcOlKsrfexxggb29w3YfozD\nF4xv0B5opsxa1GFKKatp5Ok869Uo5ZZUPWqn60kVGtenZYrIAmABQFVV1YhfJ9WV3q4/fOxxSv0+\nduw7QKAjvRKnC1d08tFflnFNyaroNmep2hE/5auuaS49Hd1516tRyi3JetQjXU+TC27t/ezoJuYi\ncg7wE2PMJZGv/wXAGPN/Ez0/203Mk/0Sh/zhs9yA3Jobb1XYC284MnwKaeGKTjpf+CN3l9x5eEA2\nZlPmTC9Iulm4UsO7ddlmPv3yv/KPo547/OCZ18Hf/dK9RjE4/ZxO7EhHvmxi/jJQLSKTgPeArwBz\nnTpYsiv9SBdSDXec1i099AfDs3PSSau0dOxiToJtzta1PE7rtslpV7aMvTA0nXk5TDl1ROegVLGJ\n7zQ1VNenvUlJLrk50OzotExjzCHg28AK4A3gUWPM604eMxEnNvaOnX51sX8jX3j/jmEXWDXWjmdN\naOqgjZkPmlH89v2J3LuqK/EFKY51p3Ll1lup2vrwiDdzVqrYJPpsNPk2Druexi1uTt10PIdvjHka\ncDUqObEBubXhyJbVf+SOUXcxprt/2BKqN19Sw0K+zM//UsY1Jas4ZEIs3HNueE9NYK2ZmrInYved\nilLFItlno+nvLstpPal0Uq1uTt10fdA2V5woJLa/b4BzJcGq2iQB+OZLauCS7wHfI9DRzeqHXwFC\nNPo2MlM20XLkF6mr8CW9IGWyj6ZSXpIPn41Mpoa7NXXTMwHfCdm8yZpqK6kZfwSVO1dGtwY8uH80\noy/7XdILhhN3KkoVAyc/G+lOkMi3RWCJaMDPQrZvsmOOGD2o7s5oczBlikZLHiuVmBOfjUx67fm4\nCCyeBvwsZfMmm3vWSTyx9TRN0SiVpzLpted7WQXQgO+qptpKmLuApW3HaIpGKZvZsVYlk157IayN\ncXThVaayXXiVjkL4oyilsmPn4qZ0YoYTi6kyke7CK0/Vw8+3UqpKqexZGwZt//03o+tS7KxL31Rb\nSUN1Bbvbnhx0jFj5Xgff4qmAXyh/FKVUehItuGoPNDOq61n+ddTvaPRtzHoANZ0Fj/leB9/iqRx+\nIYyiK6XSl2jB1d9WL+a7vtcZM6qfq8wqnp3yc5pqL7X1GPGz6QphwBY81sO3/ijXnHOS4zm2RLeZ\nSil7xZdNOSijCWGiwXmM9HP83peyOsbYshJeNFOjxxighJ4dbw35XDfVVnLbFafmbbAHj/XwITcr\n3PK5LKtSxSR+Lcy+8TN57IWtnGM6GBOzh8RIWRse9QbruYkbmOt7nnN9m6nY9QLBx9YX3OfacwE/\nF7TmjVK5E7sWpgr44gnd3LdyLJ/tfYVjTr+UuqaRF+iNHfcLBOs5TzYxK1LxthA/1xrwE8h26mY+\n1PVQyqvCd/HfseW14jc8WkdhL5T03Dz8VOyaTzvSHbZ0Szal8ktsBxDIy89nvmyAUnDsKoA0kpIL\nmvtXKv8MGfcr4FpWRTdLJ9vZMW7Op02a+1dKKRs4FvBF5Cci8p6ItEf+c7ybaseOULmcuhnPiZ25\nlFLK4nRK53ZjTM52DLZrdoxbmxNovXullJOKKoefr7NjMhmI1Xr3SimnOB3wbxCRa4A24J+NMX+L\nf4KILAAWAFRVVWV1sHzsIetArFIqX2QV8EWkBRif4Fs/BO4BfgqYyP9/BcyPf6IxZjGwGMLTMrNp\nD+RfD1kXYSml8kVWAd8Yk9aaZRG5D3gqm2M5ycm57/maZlJKeY9jKR0ROc4YszPy5ZXAZqeOlQ2n\nUy75mGZSStmnkDZVcjKH/x8iUkc4pfNX4OsOHmvEcpFyybc0k1LKHplscp4PHJuHb4z5qjFmqjHm\nNGPM38f09l0R6Ojm1mWbh+xypXPflVIjVWibKhXVtMxkhrsKa8pFKTVShbapkicCfqr6OE6mXAop\nv6eUykyh7HRl8UTAz+QqbGeALrT8nlIqc26tzB8JTwT8dK/CdgdouypvKqWUHYquWmYy6ew3afcA\nTKHsZK+U8gZP9PDjJUvb2D0AU2j5PaVUcfPcjlepdrTSQValVKHRHa+SSGfGjgZ6pVQx8kwO36J5\ndaWUV3muh695daWUV3ku4IOmbZRS3uS5lI5SSnmVJ3v4ybQHmunrbKGsppG6prluN0cppWylAT+i\nPdBMzZqbKJd+enuW0w4a9JVSRUVTOhF9nS2UR2ril0s/fZ0tLrdIKaXsVZQ9fGvLwosPPEPFEaNh\n+rVJSx5bC63qxp1Db8/ycA/flFJWk9bujUopVTCy3cT8KuAnwCnADGNMW8z3/gX4GhAEbjTGrMjm\nWOmytiy83Xc7o+VQ+MF3VsFVDw4J+oOKpZVMgNqfc/zelzSHr5QqStn28DcDs4H/in1QRGqBrwCf\nBY4HWkTkM8aYYJbHS8nasjAa7AGC/Qm3LYxfdds+5hxmz7nO6SYqpZQrssrhG2PeMMZ0JvjWFcAj\nxpiDxph3gC5gRjbHSpe1ZeFBE3Mt85cm3LZQV90qpbzEqRz+CcC6mK/fjTw2hIgsABYAVFVVZX1g\na8vCx9vGpczh66pbpZSXpAz4ItICjE/wrR8aY5Zl2wBjzGJgMYSrZWb7ehC7ZWHqbQt11a1SyitS\nBnxjzEimq7wHTIj5+sTIY0oppVzi1Dz8PwFfEZHRIjIJqAY2OHQspZRSacgq4IvIlSLyLnAO8D8i\nsgLAGPM68CjQATwLfCsXM3SUUkoll9WgrTFmKbA0yfd+Bvwsm9dXSilln6JcaRvLWnXbIJuoOvPy\npCtulVKq2BV1wLdW3f7SdydjpJ/gX5/Af9UDGvSVUp5U1MXTrFW3YyJF0fzBvvCKW6WU8qCiDvjW\nqtsDphSAoL8s4YpbpZTygqJO6Virbpe2jdMcvlLK84o64EPsqlullPK2ok7pKKWUOkwDvlJKeYQG\nfKWU8ggN+Eop5REa8JVSyiM04CullEdowFdKKY/QgK+UUh6hAV8ppTxCA75SSnlEtjteXSUir4tI\nSESmxzw+UUR6RaQ98t+92TdVKaVUNrKtpbMZmA38V4LvbTXG1GX5+koppWyS7RaHbwCIiD2tUUop\n5Rgnc/iTIumcF0SkIdmTRGSBiLSJSFtPT4+DzVFKKW9L2cMXkRZgfIJv/dAYsyzJj+0Eqowxe0Wk\nHvhvEfmsMebD+CcaYxYDiwGmT59u0m+6UkqpTKQM+MaYxkxf1BhzEDgY+fdGEdkKfAZoy7iFSiml\nbOFISkdEKkTEH/n3p4Fq4G0njqWUUio92U7LvFJE3gXOAf5HRFZEvnU+8JqItAOPA9cbY/Zl11Sl\nlFLZyHaWzlJgaYLHnwCeyOa1lVJK2avo97QdTnugmb7OFspqGqlrmut2c5RSylGeDfhPLrmPS9/8\nAWOkn96e5bSDBn2lVFHzZC2dQEc3H3U8xxjpB6Bc+unrbHG5VUop5SxPBvzWLT2sDk7lgCkF4IAp\npawm49mnSilVUDyZ0mmoruDGthncOHAD5/s3cUTtxczWdI5Sqsh5MuA31VayaM4ZtG45keOqv05T\nbaXbTVJKKcd5MuBDOOhroFdKeYknc/hKKeVFGvCVUsojNOArpZRHaMBXSimP0ICvlFIeoQFfKaU8\nQgO+Ukp5hBiTP7sKikgPsC2LlzgG2GNTcwqF187Za+cL3jtnPd/MnWSMqUj1pLwK+NkSkTZjzHS3\n25FLXjtnr50veO+c9XydoykdpZTyCA34SinlEcUW8Be73QAXeO2cvXa+4L1z1vN1SFHl8JVSSiVX\nbD18pZRSSRRkwBeRS0WkU0S6ROT7Cb4vIrIo8v3XRGSaG+20SxrnOy9ynptE5EUROd2Ndtop1TnH\nPO9METkkIl/KZfvsls75isgFItIuIq+LyAu5bqPd0nhfHykiy0XkL5FzvtaNdtpFRO4Xkd0isjnJ\n952PW8aYgvoP8ANbgU8DpcBfgNq451wGPAMIcDaw3u12O3y+5wKfivz784V8vumec8zz/gw8DXzJ\n7XY7/Dc+CugAqiJfH+t2u3Nwzj8A/j3y7wpgH1DqdtuzOOfzgWnA5iTfdzxuFWIPfwbQZYx52xjT\nDzwCXBH3nCuAh0zYOuAoETku1w21ScrzNca8aIz5W+TLdcCJOW6j3dL5GwPcADwB7M5l4xyQzvnO\nBZ40xmwHMMZ44ZwNMFZEBDiCcMA/lNtm2scYs5rwOSTjeNwqxIB/ArAj5ut3I49l+pxCkem5fI1w\nL6GQpTxnETkBuBK4J4ftcko6f+PPAJ8SkVUislFErslZ65yRzjn/GjgFeB/YBNxkjAnlpnmucDxu\neXaLw2IkIrMIB/yZbrclB+4AbjHGhMIdwKI3CqgHLgLKgZdEZJ0x5i13m+WoS4B24EJgMhAQkVZj\nzIfuNqtwFWLAfw+YEPP1iZHHMn1OoUjrXETkNOC3wOeNMXtz1DanpHPO04FHIsH+GOAyETlkjPnv\n3DTRVumc77vAXmPMx8DHIrIaOB0o1ICfzjlfC/zChBPcXSLyDjAF2JCbJuac43GrEFM6LwPVIjJJ\nREqBrwB/invOn4BrIqPeZwMfGGN25rqhNkl5viJSBTwJfLVIenwpz9kYM8kYM9EYMxF4HPhmgQZ7\nSO89vQyYKSKjRGQMcBbwRo7baad0znk74TsaRKQSqAHezmkrc8vxuFVwPXxjzCER+TawgvBI//3G\nmNdF5PrI9+8lPGvjMqALOEC4p1CQ0jzfW4FxwG8iPd5DpoCLT6V5zkUjnfM1xrwhIs8CrwEh4LfG\nmITT+wpBmn/jnwK/E5FNhGeu3GKMKdgqmiKyBLgAOEZE3gV+DJRA7uKWrrRVSimPKMSUjlJKqRHQ\ngK+UUh6hAV8ppTxCA75SSnmEBnyllPIIDfhKKeURGvCVUsojNOArpZRH/H+gcz729bG6GQAAAABJ\nRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x11f2296d8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(X_train, y_train, s=10)\n",
    "plt.scatter(X_test, y_pred, s=10)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
